﻿// Inner Fire 游戏引擎库
// UI深度图
//
// Copyright (c) 2025 by 尔西大帝. All rights reserved.
//
// 用于UI的深度图。和阴影这些使用的深度图暂时没有任何区别。
// 但是以后可能有区别，所以分开。
//
// Author: 尔西大帝
// Email: 2670613871@qq.com
// Created: 2024-01-08

#include "ui_depth_map.h"
#include <dx/core/dx_exception.h>

namespace ifire::dx {

UIDepthMap::UIDepthMap(ID3D12Device* device, UINT width, UINT height)
    : RenderTexture(device, width, height, DXGI_FORMAT_R24G8_TYPELESS) {
  BuildResource();
}

void UIDepthMap::BuildDescriptors(CD3DX12_CPU_DESCRIPTOR_HANDLE handle_cpu_srv,
    CD3DX12_GPU_DESCRIPTOR_HANDLE handle_gpu_srv,
    CD3DX12_CPU_DESCRIPTOR_HANDLE handle_cpu_dsv) {
  // 保存descriptors的handle，以便在资源重建（比如Resize）过程中重建视图。
  mCpuSrv = handle_cpu_srv;
  mGpuSrv = handle_gpu_srv;
  mCpuDsv = handle_cpu_dsv;

  // 创建descriptors
  BuildDescriptors();
}

void UIDepthMap::BuildDescriptors() {
  // 其实在UI中，这个着色器视图是不需要的，它只用DSV，但是多一个Descriptor也不影响。
  // 和其它的配合着好看。复制粘贴过来就不需要管了。

  // 创建一个指向资源的着色器资源视图（SRV），以便我们可以在着色器程序中采样阴影贴图。
  D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc = {};
  srv_desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
  srv_desc.Format = DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
  srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
  srv_desc.Texture2D.MostDetailedMip = 0;
  srv_desc.Texture2D.MipLevels = 1;
  srv_desc.Texture2D.ResourceMinLODClamp = 0.0f;
  srv_desc.Texture2D.PlaneSlice = 0;
  device_->CreateShaderResourceView(resource_.Get(), &srv_desc, mCpuSrv);

  // 创建一个指向资源的深度-模板视图（DSV），以便我们可以渲染到阴影贴图。
  D3D12_DEPTH_STENCIL_VIEW_DESC dsv_desc = {};
  dsv_desc.Flags = D3D12_DSV_FLAG_NONE;
  dsv_desc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D;
  dsv_desc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
  dsv_desc.Texture2D.MipSlice = 0;
  device_->CreateDepthStencilView(resource_.Get(), &dsv_desc, mCpuDsv);
}

void UIDepthMap::BuildResource() {
  D3D12_RESOURCE_DESC texDesc;
  ZeroMemory(&texDesc, sizeof(D3D12_RESOURCE_DESC));
  texDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
  texDesc.Alignment = 0;
  texDesc.Width = width_;
  texDesc.Height = height_;
  texDesc.DepthOrArraySize = 1;
  texDesc.MipLevels = 1;
  texDesc.Format = format_;
  texDesc.SampleDesc.Count = 1;
  texDesc.SampleDesc.Quality = 0;
  texDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
  texDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;

  D3D12_CLEAR_VALUE optClear;
  optClear.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
  optClear.DepthStencil.Depth = 1.0f;
  optClear.DepthStencil.Stencil = 0;

  // 这里的状态和ShadowMap不一样。
  // 不是READ，而是D3D12_RESOURCE_STATE_DEPTH_WRITE。
  auto default_heap = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT);
  HASSERT(device_->CreateCommittedResource(&default_heap, D3D12_HEAP_FLAG_NONE,
      &texDesc, D3D12_RESOURCE_STATE_DEPTH_WRITE, &optClear,
      IID_PPV_ARGS(&resource_)));
}

} // namespace ifire::dx